﻿using System;
using System.Threading;

namespace BackgroundTask {
    /// <summary>
    /// Declares a BackgroundAction that 
    /// can be added to a BackgroundActionPool
    /// to get results from more than one BackgroundAction
    /// </summary>
    /// <typeparam name="TParam"></typeparam>
    /// <typeparam name="TReturn"></typeparam>
    public class BackgroundAction<TParam, TReturn> {
        /// <summary>
        /// Will be raised when the action was done.
        /// Invariant to its success.
        /// </summary>
        public event EventHandler<ActionDoneEventArgs<TReturn>> OnDone;

        /// <summary>
        /// Gets or sets the underlaying Func-Object of the action.
        /// </summary>
        Func<TParam, TReturn> BGTagk { get; set; }

        /// <summary>
        /// Gets or sets the parameter to pass to the task.
        /// </summary>
        private TParam Parameter { get; set; }

        /// <summary>
        /// Gets or sets the text describing what this Task is doing.
        /// </summary>
        public String StatusText { get; set; }

        /// <summary>
        /// Initializes an action
        /// </summary>
        /// <param name="a">An Action</param>
        /// <param name="param">Actions parameter to pass</param>
        public BackgroundAction (Func<TParam, TReturn> a, TParam param)
            : this(a, null, param) {
        }

        /// <summary>
        /// Initializes an action
        /// </summary>
        /// <param name="a">An Action</param>
        public BackgroundAction (Func<TParam, TReturn> a) 
            : this(a, null, default(TParam)) {
        }

        /// <summary>
        /// Initializes an action
        /// </summary>
        /// <param name="a">An Action</param>
        /// <param name="onDone">An EventHandler that raises when the action was done</param>
        /// <param name="param">Actions parameter to pass</param>
        public BackgroundAction (Func<TParam, TReturn> a, EventHandler<ActionDoneEventArgs<TReturn>> onDone, TParam param) {
            BGTagk = a;
            Parameter = param;
            OnDone += onDone;
        }

        /// <summary>
        /// Starts the action in a new thread.
        /// Raises event "OnDone" when done.
        /// </summary>
        public void Do() {
            Thread threadDoResult = 
                new Thread(new ThreadStart(
                               delegate {
                                   try {
                                       var result = BGTagk.Invoke(Parameter);
                                       if (OnDone != null)
                                           OnDone(this, new ActionDoneEventArgs<TReturn>(result, this));
                                   } // try end
                                   catch(Exception ex) {
                                       if (OnDone != null)
                                           OnDone(this, new ActionDoneEventArgs<TReturn>(this, ex));
                                   } // catch end
                               }));
            threadDoResult.Start();
        }
    }
}